#include "stdafx.h"
#include "HandParser.h"
#include "Player.h"
#include "Action.h"
#include "Hand.h"
#include "Result.h"
#include "ActionPatcher.h"
#include <iostream>
#include <list>
#include <string>
#include <regex>

using namespace std;
using namespace tr1;

ResultType StrToResultType(string s)
{
	if (s.compare("showed") == 0)
	{
		return SHOWED;
	}
	else if(s.compare("folded") == 0)
	{
		return FOLDED;
	}
	else if(s.compare("collected") == 0)
	{
		return COLLECTED;
	}
	else
	{
		throw "String not recognized as type of result.";
	}
}

ActionType StrToActionType(string s)
{
	if (s.compare("folds") == 0)
	{
		return FOLD;
	}
	else if(s.compare("checks") == 0)
	{
		return CHECK;
	}
	else if(s.compare("calls") == 0)
	{
		return CALL;
	}
	else if(s.compare("raises") == 0)
	{
		return RAISE;
	}
	else if(s.compare("bets") == 0)
	{
		return BET;
	}
	else if(s.compare("posts") == 0)
	{
		return POST;
	}
	else
	{
		throw "String not recognized as type of action.";
	}
}

string* FindMatches(string regexString, string data)
{
	cmatch res;
	regex rx(regexString);
	regex_search(data.c_str(), res, rx);

	if (res.empty())
		return NULL;

	string* matches = new string[res.size()];
	
	for (int i = 1; i < res.size(); i++)
	{
		string match(res[i].first, res[i].second);
		matches[i-1] = match;
	}
	return matches;
}

Hand HandParser::Parse(const list<string> &lines)
{	
	list<string>::const_iterator it = lines.begin();
	list<string>::iterator it2;

	string regexp = "^PokerStars Game #(\\d+?):  Hold'em No Limit \\(\\$([0-9,.]+)/\\$([0-9,.]+) USD\\) - (\\d{4})/(\\d{2})/(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})";	
	string* idBlindsDateTime = FindMatches(regexp, *it);
	string id = idBlindsDateTime[0];
	string sb = idBlindsDateTime[1];
	string bb = idBlindsDateTime[2];
	string year = idBlindsDateTime[3];
	string month = idBlindsDateTime[4];
	string day = idBlindsDateTime[5];
	string hour = idBlindsDateTime[6];
	string minute = idBlindsDateTime[7];
	string second = idBlindsDateTime[8];
	string dateTime = year + ":" + month + ":" + day + ":" + hour + ":" + minute + ":" + second;

	it++;

	regexp = "^Table '([a-zA-Z0-9 ]+?)'.+Seat #(\\d{1,2}) is the button";	
	string* tableNameButton = FindMatches(regexp, *it);
	string tableName = tableNameButton[0];
	string button = tableNameButton[1];
	
	regexp = "^Seat (\\d{1,2}): ([a-zA-Z0-9\\@. _]+?) \\(\\$([\\d.]+?) in chips\\)";
	string* seatNumPlayerNameStack;
	list<Player> players;
	do
	{
		it++;
		seatNumPlayerNameStack = FindMatches(regexp, *it);
		if (seatNumPlayerNameStack != NULL)
		{
			players.push_back(Player(
				seatNumPlayerNameStack[1],
				atof(seatNumPlayerNameStack[0].c_str()),
				atof(seatNumPlayerNameStack[2].c_str())));
		}
	}
	while (seatNumPlayerNameStack != NULL);

	it--;

	// blind posts
	regexp = "^([a-zA-Z0-9\\@. _]+?): posts (?:small|big) blind \\$([\\d.]+)";
	string *playerSmallBigBlind;
	list<Action> actions;
	do
	{	
		it++;
		playerSmallBigBlind = FindMatches(regexp, *it);
		if (playerSmallBigBlind != NULL)
		{
			string teee = playerSmallBigBlind[1];
			actions.push_back(Action(
				playerSmallBigBlind[0],
				POST,
				atof(playerSmallBigBlind[1].c_str())));
		}
	}
	while (playerSmallBigBlind != NULL);

	// *** HOLE CARDS ***
	it++;

	regexp = "^Dealt to ([a-zA-Z0-9\\@. _]+) \\[([a-zA-Z0-9]{2}) ([a-zA-Z0-9]{2})\\]";
	string* holeCards;
	holeCards = FindMatches(regexp, *it);
	string holeCard1 = holeCards[1];
	string holeCard2 = holeCards[2];

	list<string> dealtCards;
	regexp = "^([a-zA-Z0-9\\@. _]+?): (folds|checks|bets|calls|raises)(?: \\$([\\d.]+)){0,1}";
	string regexp2 = "\\*\\*\\* (?:FLOP|TURN|RIVER) \\*\\*\\*.+\\[([a-zA-Z0-9 ]+)\\]";
	string* currentAction;
	string* dealtCard;
	do
	{
		it++;		
		currentAction = FindMatches(regexp, *it);
		if (currentAction != NULL)
		{
			actions.push_back(Action(currentAction[0], StrToActionType(currentAction[1]), atof(currentAction[2].c_str())));
		}
		else
		{
			dealtCard = FindMatches(regexp2, *it);
			if (dealtCard != NULL)
				dealtCards.push_back(dealtCard[0]);
		}
	}
	while (currentAction != NULL || dealtCard != NULL);

	it--;

	do
	{
		it++;
	}
	while ((*it).compare("*** SUMMARY ***\r\n") != 0);

	it++;

	regexp = "^Total pot \\$([\\d.]+) \\| Rake \\$([\\d.]+)";
	string* potRake;
	potRake = FindMatches(regexp, *it);

	float pot = atof(potRake[0].c_str());
	float rake = atof(potRake[1].c_str());

	regexp = "^Seat (\\d{1,2}): ([a-zA-Z0-9\\@. _]+?) (?:\\((button|small blind|big blind)\\) ){0,1}(folded|showed|collected) (?:.*?\\(\\$([\\d.]+)\\)){0,1}";
	regexp2 =".+\\[([a-zA-Z0-9]{2} [a-zA-Z0-9]{2})\\]";
	string* result;
	string* showed;
	list<Result> results;
	do
	{
		result = FindMatches(regexp, *it);
		if (result != NULL)
		{
			string action = result[3];			

			if (action == "showed")
			{
				showed = FindMatches(regexp2, *it);
				results.push_back(Result(result[1], StrToResultType(result[3]), atof(result[4].c_str()), *showed));
			}
			else
				results.push_back(Result(result[1], StrToResultType(result[3]), atof(result[4].c_str()), ""));
		}
		it++;		
	}
	while (it != lines.end());

	ActionPatcher actionPatcher;
	actionPatcher.UpdateActions(actions);

	PositionPatcher positionPatcher;
	positionPatcher.Patch(players, atoi(button.c_str()));


	return Hand(tableName, id, atof(sb.c_str()), atof(bb.c_str()), dateTime, atoi(button.c_str()), holeCard1,
		holeCard2, dealtCards, results, players, actions);
}